%Chap04-Final Preparations
%UTF8-
%

\chapter{最后准备}
\section{关于 \$LFS}
\verb|LFS| 变量的使用贯穿本书的始末，因此确保已定义这个变量至关重要。变量的值应该设置为 LFS 分区的挂载点。请使用如下命令检查是否已正确设置了 \verb|LFS| 变量的值。

\begin{cmd}
echo LFS
\end{cmd}

确保上文的输出就是你的 LFS 分区的挂载点。在后续我们使用 \verb|/mnt/lfs| 作为例子来指代该变量。如果输出不正确，那么可以使用如下的命令设置如下变量：

\begin{cmd}
export LFS=/mnt/lfs
\end{cmd}

设置了 \verb|LFS| 变量的一个好处是类似于 \verb|mkdir $LFS/toos| 的命令可以直接使用。shell 在处理命令行时会自动替换 ``\$LFS'' 为为 ``/mnt/lfs'' （或者是你设置的其他路径）。

在你切换上下文环境时，请记得检查是否设置了 \verb|\$LFS| 变量（比如你使用 \verb|su| 切换到 \verb|root| 或者其他用户时）。

\section{创建 \$LFS/tools 目录}
所有在第五章中编译的软件会安装在 \verb|\$LFS/tools|，以与第六章中要编译的程序分离开来。这里编译的程序是临时工具，不会被应用到最综合那个的 LFS 系统中。通过分离这些程序到单独的目录，我们可以在使用它们后轻松地抛弃它们。这同时也可以预防这些程序留在主机生产目录中（在第五章中偶然情况下很容易出现）。

以 \verb|root| 用户执行如下命令，以创建需要的目录：

\begin{lstlisting}
mkdir -v $LFS/tools
\end{lstlisting}

先一步就是在主机系统上创建 \verb|tools| 的符号链接。这个链接指向 LFS 分区上新创建的目录。同样，使用 \verb|root| 用户执行如下命令：

\begin{lstlisting}
ln -sv $LFS/tools /
\end{lstlisting}

上述内容是正确的。ln命令有一些句法的变种，因此在你报告任何错误前，请检查 \textbf{info coreutils ln} 以及\verb|ln(1)|。 

新创建的符号链接允许我们编译工具链，因此它一直执行 \verb|/tools|，这意味着在第五章（那时我们还再使用主机的一些工具）和后续的章节（当我们切换根用户\footnote{chrooted}到 LFS 分区时）中，编译器、汇编器、链接器仍然能够工作。

\section{添加 LFS 用户}
以root用户登录时，稍不小心就会导致一场灾难，甚至于摧毁整个系统。因此，我们建议使用一个非特权用户\footnote{unprivileged user}构建本章中的软件包。你可以使用你自己的用户名，但是为了减少设置一个干净的工作环境的工作，我们新建名为 \verb|lfs| 的新用户和新的组，之后我们呢就可以在安装过程中使用这个用户。以 \verb|root| 身份执行如下命令，以添加我们的新用户：

\begin{lstlisting}
groupadd lfs
useradd -s /bing/bash -g lfs -m -k /dev/null lfs
\end{lstlisting}

命令行中各选项的含义如下：
\begin{description}
\item[\emph{-s /bin/bash}] \hfill \\
使用 \textbf|bash| 作为 \verb|lfs| 用户的默认 shell。

\item[\emph{-g lfs}] \hfill \\
添加 \verb|lfs| 用户到 \verb|lfs| 组。

\item[\emph{-m}] \hfill \\
创建 \verb|lfs| 用户的家目录。

\item[\emph{-k /dev/null}]  \hfill \\
这个选项把家目录的输入位置定义为空设备，以防止可能从骨架目录\footnote{skeleton directory}（默认为 \verb|/etc/skel|）发生的文件拷贝。

\item[\emph{lfs}] \hfill \\
这是我们创建的组和用户的名字。

\end{description}

为 \verb|lfs|用户创建密码，以支持 \verb|lfs| 用户登录（相对于以 \verb|root| 用户登录，然后切换为 \verb|lfs|用户而说，后一种不需要密码）：

\begin{lstlisting}
passwd lfs
\end{lstlisting}

设置 \verb|lfs| 用户为 \verb|\$LFS\tools| 的属主：

\begin{lstlisting}
chown -v lfs $/LFS/tools
\end{lstlisting}

如果你按照上文的建议设置了单独的工作目录，那么设置 \verb|lfs| 为改目录的属主：
\begin{lstlisting}
chown -v lfs $LFS/sources
\end{lstlisting}

然后，以 \verb|lfs| 用户登录，可以通过一个虚拟终端\footnote{virtual console}，显示管理器，或者如下的用户切换命令：

\begin{lstlisting}
su - lfs
\end{lstlisting}

\verb|su| 后的 ``-'' 表示启动该用户的登录 shell，而不是非登录 shell。关于这两者的区别请参考 \verb|bash(1)| 和 \textbf{info bash}。

\section{设置环境}
通过为 \verb|bash| shell 新建两个启动文件，我们可以设置一个很好的工作环境。以 \verb|lfs| 用户登录后，执行如下命令以创建一个新的 \verb|.bash_profile|:

\begin{lstlisting}
cat > ~/.bash_profile << "EOF"
exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash
EOF
\end{lstlisting}

我们使用 \verb|lfs| 用户登录时，初始化的 shell 通常是一个登录 shell\footnote{login shell}，这个 shell 读取主机的 \verb|/etc/profile| 文件（可能包含一些设置和环境变量），之后会读取 \verb|.bash_profile|。\verb|.bash_profile| 中的 \verb|exec env -i \ldots /bin/bash| 命令会替换当前 shell 为一个空的新 shell，这个 shell 只设置了 \verb|HOME|， \verb|TERM|， \verb|PS1| 变量。我们这样做以确保不会从主机系统继承任何我们不需要的有潜在的风险的环境变量。使用这种处理技巧，我们能够得到一个干净的环境。

新的 shell 实例是一个\emph{非登录} shell，这表示它不会读取 \verb|/etc/profile| 或者 \verb|.bash_profile|文件，而是读取 \verb|.bashrc| 文件。因此，我们创建如下的 \verb|.bashrc| 文件：
\begin{lstlisting}
cat > ~/.bashrc << "EOF"
set +h
umask 022
LFS=/mnt/lfs
LC_ALL=POSIX
LFS_TGT=$(uname -m)-lfs-linux-gnu
PATH=/tools/bin:/bin:/usr/bin
export LFS LC_ALL LFS_TGT PATH
EOF
\end{lstlisting}

\verb|set +h| 命令禁用 bash 的 hash 函数。通常情况下，hash 是一种很有用的特性，bash 可以使用 哈希表\footnote{hash table}来记录可执行文件的完整路径，以避免查找同样的可执行文件时对 \verb|PATH| 进行重复的搜索。一旦新的工具安装完成，我们就应该使用新的工具。通过禁用这个函数，shell 就能够在程序运行时重新扫描 \verb|PATH|。同样的，这使得 \verb|$LFS/toos| 中新编译的工具在编译完成后就可以使用，shell 也能够立即发现它，而不是使用这个程序在其他位置的一个另外的版本。

设置用户文件创建掩码（umask）为 022，以保证新创建的文件和目录是只有属主可写的，同时可以被所有用户读取和执行（假设 \verb|open(2)| 系统调用的使用默认的模式，那么新文件的权限会是 644，目录的默认权限为 755）。

\verb|LFS| 变量需要设置为选定的挂载点。

\verb|LC_ALL| 变量控制特定程序的本地化，使得他们的信息跟随不同国家的风俗。如果主机系统使用的 Glibc版本小于2.2.4，那么设置\verb|LC_ALL|为``POSIX''或者``C''（在本章中）的话，在你退出切换根用户环境后可能会引起问题，那时就需要重新再来一遍了。设置\verb|LC_ALL|为``POSIX''或者``C''（这两者是等价的）以确保所有事务都能工作（当然，在切换的跟用户环境下除外）。

\verb|LFS_TGT|变量设置了一个非默认的，但是兼容的机器描述，这在我们构建我们交叉编译器和链接器以及交叉编译我们临时工具链的时候很有用。更多的信息我们在第5.2节的``工具链技巧须知''中讨论。

通过把\verb|/tools/bin|放在标准\verb|PATH|的首位，在第五章中安装的程序可以在他们安装完成后立即就被shell获取到。这和关闭hash结合起来，限制了当我们在第五章环境中生成同名程序后，系统还是使用主机上老的程序的风险。

最后，要在构建临时工具前完全准备我们的环境，需要刷新我们刚创建的用户配置文件：
\begin{lstlisting}
source ~/.bash_profile
\end{lstlisting}

\section{标准构建单元}
许多人都想预先能够知道编译和安装每个包所花费的精确的时间。因为LFS可以构建在许多不同的系统上，所以不可能提供精确的时间估计。最大的软件包（Glibc）需要在最快的系统上需要花费大约20分钟的时间来编译，但是在较慢的系统上可能需要多达3天的时间！相对于提供实际的时间，我们将会使用标准构建单元\footnote{Strandard Build Unit}（SBU）估量的办法。

SBU估量按照如下流程工作。本书中第一个要编译的包时第五章中的Binutils。编译这个包所花费的时间将作为标准构建单元，或者成为SBU。所以其他包都以相对于这个时间的方式来进行描述。

举个例子，假设一个包的编译时间是4.5SBUs。这表明如果一个系统在第一轮编译很安装Binutils时消耗的时间是10分钟，那么，构建例子中这个包的时间\emph{大约为}45分钟。幸运的是，大部分包的构建时间都是小于Binutils的构建时间的。

通常情况下，SBUs不是完全准确的，因为他们依赖于多方面的因素，比如主机系统GCC的版本。我们提供这些数据主要是为了估计安装一个包所需要花费的大致时间，但是在有些情况下，真实的时间与估计可能会差距多达几十分钟。

如果想了解不同配置的机器所花费的具体时间，我们推荐访问LFS的SBU主页：\url{http://www. linuxfromscratch. org/~sbu/}。

\begin{note}
在很多现代的多核心系统上，可以使用``并行构建''\footnote{parallel make}技术来减少编译一个包的时间。这个可以通过设置一个环境变量或者告诉\verb|make|程序有多少可用核心来启用。例如，Core2Duo核 支持两个并发进程：
\begin{lstlisting}
export MAKEFLAGS='-j 2'
\end{lstlisting}
或者直接使用参数构建：
\begin{lstlisting}
make -j2
\end{lstlisting}
按照这种方式使用多核心的话，本书中的SBU单元可能会有很大变化，甚至可能比正常编译消耗的时间还要多。分析构建进程的输出也更困难，因为各个进程的输出将会交叉出现。如果你在构建过程中遇到了问题，那么请设置编译核心为单处理器，这样分析错误更方便些。
\end{note}

\section{测试套件}
大部分的包都提供了测试套件。对新构建的包执行这些测试套件是个好的主意，因为这样可以提供一个``健全检查''\footnote{sanity check}以表征所有的功能都是正确编译的。如果通过了测试套件的一系列检查，那么通常这个软件就实现了按照开发人员的期望的功能。但是即使这样，这也不能保证软件是不存在bug的。

有些测试组件比其他的要重要。例如，一些核心工具链软件（GCC，Binutils，Glibc）的测试套件是最为重要的，因为他们是我们正常构建系统的最主要部分 。GCC和Glibc的测试套件可能要执行很长时间才能完成，尤其是在一些比较慢的硬件上。虽然如此，我们还是建议你执行这些测试。

\begin{note}
实际经验表明，执行第五章的测试并不能使我们获得多少益处。甚至有时主机系统也会对测试有些影响，导致会出现一些难以理解的现象和失败。因为第五章的工具只是暂时使用，以后就会抛弃，因此，对于普通读者，我们不建议在第五章执行这些测试套件。执行测试套件的说明是给测试人员和开发者准备的，但是这也是仅仅只是可选的工作。
\end{note}

执行Binutils和GCC测试套件过程中经常遇到的一个问题是伪终端\footnote{pseudo terminals}(PTYs)不足。这会因此大量的测试失败。发生这个问题可能有不少原因，但是最主要的原因是因为主机系统没有正确设置 \verb|devpts| 文件系统。在 \url{http://www. inuxfromscratch.org//fs/faq. html#no- ptys} 上有关于这个问题的很详细讨论。

有时测试套件会失败，但是因为某些原因开发人员会意识到这些错误并认为无关紧要。请参考位于 \url{http://www.linuxfromscratch.org/lfs/build-logs/6. 8/} 以决定是否应该出现这些错误。这个站点在本书中的所有测试中都是可用的。






